<template>
  <div class="class-c">
    <h2>{{ name }}</h2>
    <!--zIndex 如果是绝对和相对定得就可以使用-->
    <!--    TODO 这个值无法使用-->
    <!--    :sort-value-by="settings.sortValueBy"-->
    <TreeSelect
      v-model="value"
      :allow-clearing-disabled="settings.allowClearingDisabled"
      :allow-selecting-disabled-descendants="settings.allowSelectingDisabledDescendants"
      :always-open="settings.alwaysOpen"
      :append-to-body="settings.appendToBody"
      :async="settings.async"
      :auto-focus="settings.autoFocus"
      :auto-load-root-options="settings.autoLoadRootOptions"
      :auto-deselect-ancestors="settings.autoDeselectAncestors"
      :auto-deselect-descendants="settings.autoDeselectDescendants"
      :auto-select-ancestors="settings.autoSelectAncestors"
      :auto-select-descendants="settings.autoSelectDescendants"
      :backspace-removes="settings.backspaceRemoves"
      :before-clear-all="settings.beforeClearAll"
      :branch-nodes-first="settings.branchNodesFirst"
      :cache-options="settings.cacheOptions"
      :clearable="settings.clearable"
      :clear-all-text="settings.clearAllText"
      :clear-on-select="settings.clearOnSelect"
      :clear-value-text="settings.clearValueText"
      :close-on-select="settings.closeOnSelect"
      :default-options="settings.defaultOptions"
      :delete-removes="settings.deleteRemoves"
      :delimiter="settings.delimiter"
      :flatten-search-results="settings.flattenSearchResults"
      :disable-branch-nodes="settings.disableBranchNodes"
      :disabled="settings.disabled"
      :disable-fuzzy-matching="settings.disableFuzzyMatching"
      :flat="settings.flat"
      :instance-id="settings.instanceId"
      :join-values="settings.joinValues"
      :limit="settings.limit"
      :limit-text="settings.limitText"
      :loading-text="settings.loadingText"
      :load-options="settings.loadOptions"
      :match-keys="settings.matchKeys"
      :max-height="settings.maxHeight"
      :multiple="settings.multiple"
      :name="settings.name"
      :no-children-text="settings.noChildrenText"
      :no-options-text="settings.noOptionsText"
      :no-results-text="settings.noResultsText"
      :normalizer="settings.normalizer"
      :open-direction="settings.openDirection"
      :open-on-click="settings.openOnClick"
      :open-on-focus="settings.openOnFocus"
      :options="options"
      :placeholder="settings.placeholder"
      :required="settings.required"
      :retry-text="settings.retryText"
      :retry-title="settings.retryTitle"
      :searchable="settings.searchable"
      :search-nested="settings.searchNested"
      :search-prompt-text="settings.searchPromptText"
      :show-count="settings.showCount"
      :show-count-of="settings.showCountOf"
      :show-count-on-search="settings.showCountOnSearch"
      :sort-value-by="settings.sortValueBy"
      :tab-index="settings.tabIndex"
      :value="settings.value"
      :value-consists-of="settings.valueConsistsOf"
      :value-format="settings.valueFormat"
      :z-index="settings.zIndex"
      @open="open"
      @close="close"
      @input="input"
      @select="select"
      @deselect="deselect"
      @search-change="searchChange"
    />
  </div>
</template>

<script>
import TreeSelect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import _ from 'lodash'
import {getRealUrl} from "@/utils/httpRequet";
import request from "@/components/form-making/util/request";

export default {
  name: 'PsTreeSelect',
  components: {
    TreeSelect
  },
  props: {
    treeCompData: {
      type: Object,
      default: () => {
        return {
          name: '', // 填写标注
          treeData: [],
          treeBuildConfig: {},
        }
      }
    }
  },
  data() {
    return {
      name: '',
      mode: 'manual',
      treeConfigKey: '',
      dataUrl: getRealUrl('defaultTreeDataUrl', true),
      value: null,
      checkType: '2',
      converData: {
        enable: true,
        idKey: 'id',
        pIdKey: 'pId',
        value: 'name',
        standTreeModel: {
          children: 'children',
          id: 'name',
          value: ''
        }
      },
      settings: {
        // 即使禁用了选定的节点，是否也允许重置值。
        allowClearingDisabled: false,
        // 选择/取消选择祖先节点时，是否应该选择/取消选择其禁用的后代。您可能希望将其与 allowClearingDisabled 结合使用。
        allowSelectingDisabledDescendants: false,
        // 菜单是否始终打开
        alwaysOpen: false,
        // 将菜单追加到.
        appendToBody: false,
        // 是否启用 异步搜索模式.
        async: false,
        // 自动将组件聚焦在安装座上。
        autoFocus: false,
        // 在装入时自动加载root选项。设置false, 为时，打开菜单时将加载根选项。
        autoLoadRootOptions: false,
        // 当用户取消选择节点时，将自动取消选择其祖先。仅适用于平面模式。
        autoDeselectAncestors: false,
        // 当用户取消选择节点时，将自动取消选择其后代。仅适用于平面模式。
        autoDeselectDescendants: false,
        // 当用户选择节点时，将自动选择其祖先。仅适用于平面模式。
        autoSelectAncestors: false,
        // 当用户选择一个节点时，将自动选择其后代。仅适用于平面模式。
        autoSelectDescendants: false,
        // Backspace如果没有文本输入，是否删除最后一项。
        backspaceRemoves: true,
        // 在清除所有输入字段之前处理的功能。返回 false 到要清除的停止值。
        beforeClearAll: () => true,
        // 在叶节点之前显示分支节点。
        branchNodesFirst: false,
        // 是否为 异步搜索模式缓存每个搜索请求的结果。
        cacheOptions: true,
        // 是否显示重置值的“×”按钮。
        clearable: true,
        // 时“×”按钮的标题 :multiple="true". Type: String Default: "Clear all"
        clearAllText: '清除所有文本',
        // 选择选项后是否清除搜索输入。仅在时使用 :multiple="true"。对于单选模式，无论prop值如何，它始终在选择后清除输入。
        clearOnSelect: false,
        // 	“×”按钮的标题。Type: String Default: "Clear value"
        clearValueText: '清空...',
        /**
         * 选择选项后是否关闭菜单。仅在时使用 :multiple="true".
         * Type: Boolean
         * Default: true
         */
        closeOnSelect: true,
        /**
         * 加载时应自动扩展多少级分支节点。设置 Infinity 为默认使所有分支节点扩展。
         * Type: Boolean | node[]
         * Default: false
         */
        defaultOptions: false,
        /**
         * Delete 如果没有文本输入，是否删除最后一项。
         * Type: Boolean
         * Default: true
         */
        deleteRemoves: true,
        /**
         * 用于连接隐藏字段值的多个值的定界符。
         * Type: String
         * Default: ","
         */
        delimiter: ',',
        /**
         * 搜索时是否展平树（仅同步搜索模式）。例如参见 here
         * Type: Boolean
         * Default: false
         */
        flattenSearchResults: false,
        /**
         * 是否阻止选择分支节点。例如参见here
         * Type: Boolean
         * Default: false
         */
        disableBranchNodes: false,
        /**
         * 是否禁用控件。
         * Type: Boolean
         * Default: false
         */
        disabled: false,
        /**
         * 设置为true 禁用默认情况下启用的模糊匹配功能。
         * Type: Boolean
         * Default: false
         */
        disableFuzzyMatching: false,
        /**
         * 是否启用平面模式。详细信息请参见here
         * Type: Boolean
         * Default: false
         */
        flat: false,
        /**
         * 将所有事件作为最后一个参数传递。对于识别事件来源很有用。
         *  Type: String | Number
         * Default: "<auto-incrementing number>$$"
         */
        instanceId: '<auto-incrementing number>$$',
        /**
         * 使用 delimiter （旧版模式）将多个值连接到单个表单字段中。
         * Type: Boolean
         * Default: false
         */
        joinValues: false,
        /**
         * 限制所选选项的显示。其余的将隐藏在limitText 字符串中。
         * Type: Number
         * Default: Infinity
         */
        limit: Infinity,
        /**
         * 当所选元素超过定义的限制时处理显示的消息的功能。
         * Type: Fn(count) 🡒 String
         * Default: count => `and ${count} more`
         */
        limitText: count => `and ${count} more`,
        /**
         * 加载选项时显示的文本。
         *  Type: String
         * Default: "Loading..."
         */
        loadingText: '加载...',
        /**
         * 用于动态加载选项。详细信息请参见 here
         * 可能的值action: "LOAD_ROOT_OPTIONS", "LOAD_CHILDREN_OPTIONS" or "ASYNC_SEARCH".
         * callback - 接受可选 error 参数的函数
         * parentNode - 仅在加载子选项时显示
         * searchQuery - 仅在搜索异步选项时显示
         * instanceId - instanceId 等于传递给vue-treeselect 的prop 的值
         * Type: Fn({action, callback, parentNode?, instanceId}) 🡒 (void | Promise)
         * Default: –
         */
        loadOptions: undefined,
        /**
         * node 要过滤对象的哪些键。
         * Type: String[]
         * Default: [ "label" ]
         */
        matchKeys: ['label'],
        /**
         * 设置 maxHeight 菜单的样式值。
         * Type: Number
         * Default: 300
         */
        maxHeight: 300,
        /**
         * 设置 true为允许选择多个选项（又名多重选择模式）。
         * Type: Boolean
         * Default: false
         */
        multiple: false,
        /**
         * <input /> 使用此字段名称为html表单生成一个隐藏标签。
         *  Type: String
         * Default: –
         */
        name: undefined,
        /**
         * 当分支节点没有子节点时显示的文本。
         *  Type: String
         * Default: "No sub-options."
         */
        noChildrenText: '没有子选项',
        /**
         * 没有可用选项时显示的文本。
         *  Type: String
         * Default: "No options available."
         */
        noOptionsText: '暂无选项...',
        /**
         * 没有匹配的搜索结果时显示的文本。
         * Type: String
         * Default: "No results found..."
         */
        noResultsText: '没有返回结果...',
        /**
         * 用于规范化源数据。详细信息请参见 here
         * Type: Fn(node, instanceId) 🡒 node
         * Default: node => node
         */
        normalizer: node => node,
        /**
         * Default: "auto"  默认情况下（"auto"），
         * 菜单将在控件下方打开。如果没有足够的空间，vue-treeselect将自动翻转菜单。
         * 您可以使用其他四个选项之一来强制菜单始终按指定的方向打开。
         * 可接受的值："auto", "below", "bottom", "above" 或 "top".
         *  Type: String
         * Default: "auto"
         */
        openDirection: 'auto',
        /**
         * 单击控件时是否自动打开菜单。
         * Type: Boolean
         * Default: true
         */
        openOnClick: true,
        /**
         * 控件集中时是否自动打开菜单。
         * Type: Boolean
         * Default: false
         */
        openOnFocus: false,
        /**
         * 可用选项的数组。请参阅 here 以了解如何定义它们。
         * Type: node[]
         * Default: –
         */
        options: undefined,
        /**
         * 字段占位符，无值时显示。
         * Type: String
         * Default: "Select..."
         */
        placeholder: '请选择...',
        /**
         * required在需要时应用HTML5 属性。
         * Type: Boolean
         * Default: false
         */
        required: false,
        /**
         * 显示的文本询问用户是否重试加载子项选项。
         * Type: String
         * Default: "重新加载?"
         */
        retryText: '重新加载?',
        /**
         * 重试按钮的标题。
         * Type: String
         * Default: "Click to retry"
         */
        retryTitle: '点击重试',
        /**
         * 是否启用搜索功能。
         * Type: Boolean
         * Default: true
         */
        searchable: true,
        /**
         * 设置 true 搜索查询是否也应在所有祖先节点中搜索。例如参见 here
         * Type: Boolean
         * Default: false
         */
        searchNested: false,
        /**
         * 提示您进行异步搜索的文字提示。用于 异步搜索模式。
         * Type: String
         * Default: "正在查询中..."
         */
        searchPromptText: '正在查询中...',
        /**
         * 是否显示子项计数在每个分支节点的标签旁边。例如参见 here
         *  Type: Boolean
         * Default: false
         */
        showCount: false,
        /**
         * 与一起使用 showCount 以指定应显示的计数类型。
         * 可接受的值："ALL_CHILDREN", "ALL_DESCENDANTS", "LEAF_CHILDREN" or "LEAF_DESCENDANTS".
         * Type: String
         * Default: "ALL_CHILDREN"
         */
        showCountOf: 'ALL_CHILDREN',
        /**
         * 搜索时是否显示孩子数。后退到showCount未指定时的值。
         * Type: Boolean
         * Default: –
         */
        showCountOnSearch: undefined,
        /**
         * 所选选项应按触发顺序显示并按 value 数组排序。仅在时使用:multiple="true".。例如参见here
         * 可接受的值："ORDER_SELECTED", "LEVEL" or "INDEX".
         * Type: String
         * Default: "ORDER_SELECTED"
         * TODO 这个字段出现了BUG 是否需要删除
         */
        sortValueBy: 'ORDER_SELECTED',
        /**
         * 控件的Tab索引。
         * Type: Number
         * Default: 0
         */
        tabIndex: 0,
        /**
         * 控件的值。
         * 时应为id node 对象 :multiple="false"，或时应为 id or node 对象的数组:multiple="true"。其格式取决于valueFormat 道具。
         * 在大多数情况下，请v-model改用。
         * Type: id | node | id[] | node[]
         * Default: –
         */
        value: undefined,
        /**
         * value 在多选模式下，数组中应包括哪种节点。例如参见here
         * 可接受的值："ALL", "BRANCH_PRIORITY","LEAF_PRIORITY" or "ALL_WITH_INDETERMINATE".
         * Type: String
         * Default: "BRANCH_PRIORITY"
         */
        valueConsistsOf: 'BRANCH_PRIORITY',
        /**
         * value 道具格式
         * 请注意，设置为时"object"，中的每个对象只需要 id & label 属性。可接受的值：或。nodevalue.
         * Acceptable values: "id" or "object".
         * Type: String
         * Default: "id"
         */
        valueFormat: 'id',
        /**
         * z-index 菜单中的.
         * Type: Number | String
         * Default: 999
         */
        zIndex: 999
      },
      treeData: [],
      // 设置为null, 让树进行延迟加载
      options: null,
      treeconfigurl: 'treeConfigUrl'
    }
  },
  computed: {},
  watch: {
    treeCompData: {
      handler(val, oldVal) {
        console.log('监听器的:' + val.treeBuildConfig.treeData)
        this.initSettings(val)
      },
      deep: true, // true 深度监听
      immediate: true
    }
  },
  created() {
    if (this.converData.enable === true) {
      // console.log("我来啦：：：：：",this.treeData);
      // debugger;
      console.log('this.treeData:', this.treeData)
      const tempTreeData = _.cloneDeep(this.treeData)
      this.options = this.converTreeData(tempTreeData)
      console.log(JSON.stringify(this.options))
    }
  }, mounted() {

  },
  methods: {
    initSettings: function (val) {
      const that = this
      const config = val.treeBuildConfig
      this.name = _.isNull(val.name) ? this.name : val.name
      // 加载树标识
      this.treeConfigKey = _.isNull(val.treeConfigKey) ? this.treeConfigKey : val.treeConfigKey
      // 加载树的Url
      this.dataUrl = _.isNull(val.dataUrl) ? this.dataUrl : val.dataUrl
      this.checkType = _.isNull(config.checkType) ? this.checkType : config.checkType
      this.treeData = _.isEmpty(val.treeData) ? [] : val.treeData
      this.mode = _.isNull(config.mode) ? this.mode : config.mode

      if (!_.isEmpty(config.converData)) {
        _.forEach(config.converData, function (value, key) {
          that.converData[key] = config.converData[key]
        })
      }

      if (!_.isEmpty(config.settings)) {
        _.forEach(config.settings, function (value, key) {
          // console.log(key,value);
          that.settings[key] = config.settings[key]
        })
      }
      // console.log('cccc:', JSON.stringify(this.settings))
    },
    converTreeData: function (treeData) {
      const newNodes = this.transformTozTreeFormat(this.converData, treeData)
      return newNodes
    },
    nodeChildren: function (converData, node, newChildren) {
      if (!node) {
        return null
      }
      var key = converData.standTreeModel.children
      if (typeof newChildren !== 'undefined') {
        node[key] = newChildren
      }
      return node[key]
    },
    // 简单结构转化为标准树形结构
    transformTozTreeFormat: function (converData, sNodes) {
      var i;
      var l
      var key = converData.idKey
      var parentKey = converData.pIdKey
      var valueKey = converData.value
      if (!key || key === '' || !sNodes) return []
      // eslint-disable-next-line no-undef
      if (_.isArray(sNodes)) {
        var r = []
        var tmpMap = {}
        for (i = 0, l = sNodes.length; i < l; i++) {
          // 替换valueKey
          tmpMap[sNodes[i][key]] = this.changeFiledName(valueKey, 'label', sNodes[i])
        }
        for (i = 0, l = sNodes.length; i < l; i++) {
          var p = tmpMap[sNodes[i][parentKey]]
          if (p && sNodes[i][key] !== sNodes[i][parentKey]) {
            var children = this.nodeChildren(converData, p)
            if (!children) {
              children = this.nodeChildren(converData, p, [])
            }
            children.push(sNodes[i])
          } else {
            r.push(sNodes[i])
          }
        }
        return r
      } else {
        return [sNodes]
      }
    },
    changeFiledName: function (oldVal, newVal, node) {
      node[newVal] = node[oldVal]// 修改属性名为newVal
      delete node[oldVal]// 删除oldVal
      return node
    },
    open: function (instanceId) {
      console.log('菜单打开时执行', instanceId)
    },
    close: function (value, instanceId) {
      console.log('菜单关闭时发出', value, instanceId)
    },
    input: function (value, instanceId) {
      console.log('值更改时发出', value, instanceId)
    },
    select: function (value, instanceId) {
      console.log('选择一个选项后发出', value, instanceId)
    },
    deselect: function (node, instanceId) {
      console.log('取消选择一个选项后发出', node, instanceId)
    },
    searchChange: function (searchQuery, instanceId) {
      console.log('搜索查询更改后发出。', searchQuery, instanceId)
    },
    // 加载数据选项
    async loadOptions({action, parentNode, callback}) {
      // Typically, do the AJAX stuff here.
      // Once the server has responded,
      // assign children options to the parent node & call the callback.
      let treeConfig = {};

      function loadTreeConfig() {
        request({
          url: this.treeconfigurl,
          data: {flag: this.treeConfigKey},
          method: 'post'
        }).then(data => {
          if (data.category) {
            console.log(data)
            treeConfig = data.category
          }
        })
      }

      function loadTreeData() {
        // 1. 先判断是否有ID, 如果没有则请求一次
        if (_.isEmpty(treeConfig.queryTemplet)) loadTreeConfig()
        // 如果任然没有,则返回null
        if (_.isEmpty(treeConfig.queryTemplet)) return null
        request({
          url: this.dataUrl,
          method: 'post',
          // 'ALL' 查询整颗树, 'SUB'查询下级, 用于异步
          data: {pid: parentNode.id, templet: treeConfig.queryTemplet, level: 'SUB'}
        }).then(data => {
          console.log(data)
          if (data.data) {
            return data.data
          }
        })
        return null
      }

      if (action === LOAD_CHILDREN_OPTIONS) {
        var data = loadTreeData();
        console.log(data)
      }
    },
  }

}
</script>

<style scoped>

</style>
